/*
 * @(#)ModelSwarm.java			0.1 21/11/2010
 * Copyright (C) 2010 Grupo de Alunos abaixo
 * 
 * Universidade Federal do ABC
 * Vida Artificial - 3o quadrimestre de 2010
 * Aluno: Abner
 * Aluno: Cláudio Antônio Peanho
 * Aluno: Fabrizio Borelli
 * Aluna: Maitê Balhester
 * Aluno: Rafael Munhoz
 * Professora Dr. Karla Vittori
 * Projeto: Simulação de Colônia de Formigas (antcolonyswarm)
 * 
 * Código baseado em jheatbugs-3.0 de Timothy Howe
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package br.edu.ufabc.va.acs.model;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import br.edu.ufabc.va.acs.controller.GraphicObject;
import br.edu.ufabc.va.acs.model.agent.Ant;
import br.edu.ufabc.va.acs.model.agent.AntFactory;
import br.edu.ufabc.va.acs.model.agent.Food;

import br.edu.ufabc.va.acs.util.ConfigurationLoader;

import swarm.Globals;

import swarm.Selector;

import swarm.activity.ActionGroup;
import swarm.activity.ActionGroupImpl;
import swarm.activity.Activity;
import swarm.activity.FActionForEach;
import swarm.activity.Schedule;
import swarm.activity.ScheduleImpl;

import swarm.defobj.FArgumentsImpl;
import swarm.defobj.FCallImpl;
import swarm.defobj.Zone;

import swarm.objectbase.Swarm;
import swarm.objectbase.SwarmImpl;

/**
 * Encapsula a simulação, controla a taxa de repetição, iterações, mapa e etc.
 * 
 * @author Peanho
 * 
 */
public class ModelSwarm extends SwarmImpl {

	/** número de formigas na simulação */
	public int					numOfAnts	= 50;

	/** mundo das formigas */
	private AntWorld			world;

	/** lista de formigas na simulação */
	private List<Ant>			antList;

	/** lista com os objetos gráficos, formigas, comida, obstáculos e etc */
	private List<GraphicObject>	graphicObjectsList;

	private FActionForEach		actionForEach;

	private Schedule			modelSchedule;

	/**
	 * Retorna nova instância desta classe configurada para operar na área de
	 * memória especificada por {@code zone}.
	 * 
	 * @param zone
	 *            área de memória em que este objeto irá residir
	 */
	public ModelSwarm(Zone zone) {
		super(zone);
		Properties configuration = ConfigurationLoader.getConfiguration();
		numOfAnts = Integer.parseInt(configuration
				.getProperty("world.num-of-bugs"));
		// TODO criar probe para monitaração de variáveis durante a execução
	}

	@Override
	public Object buildObjects() {
		super.buildObjects();

		// construir novo mundo
		Properties configuration = ConfigurationLoader.getConfiguration();
		world = new SingleGridWorld(getZone(), configuration);
		int colonyXPos = Integer.parseInt(configuration
				.getProperty("map.colony-x"));
		int colonyYPos = Integer.parseInt(configuration
				.getProperty("map.colony-y"));
		Point colonyPos = new Point(colonyXPos, colonyYPos);
		// TODO inserir objetos Food e obstáculos na lista
		graphicObjectsList = new ArrayList<GraphicObject>();
		antList = new ArrayList<Ant>();
		for (int i = 0; i < numOfAnts; i++) {
//			Ant ant = AntFactory.createDeneubourgAnt(world, colonyPos);
			Ant ant = AntFactory.createOrdinaryAnt(world, colonyPos);
			antList.add(ant);
			graphicObjectsList.add(ant);
		}
		
		int foodSourceX = Integer.parseInt(configuration.getProperty("map.food-source-x"));
		int foodSourceY = Integer.parseInt(configuration.getProperty("map.food-source-y"));
		Food food = new Food(32000, 127, 64, foodSourceX, foodSourceY);
		graphicObjectsList.add(food);
		world.addFoodSourceAt(food, foodSourceX, foodSourceY); 
		return this;
	}

	@Override
	public Object buildActions() {
		super.buildActions();

		ActionGroup modelActions = new ActionGroupImpl(getZone());
		try {
			modelActions.createActionTo$message(world,
					new Selector(world.getClass(), "modelStep", false));
		} catch (Exception e) {
			System.err.println("Exceção na atualização do modelo : "
					+ e.getMessage());
		}

		try {
			Ant ant = antList.get(0);
			Selector selector = new Selector(ant.getClass(), "move", false);
			actionForEach = modelActions.createFActionForEachHomogeneous$call(
					antList, new FCallImpl(this, ant, selector,
							new FArgumentsImpl(this, selector)));
		} catch (Exception e) {
			System.err.println("Exceção na movimentação das formigas: "
					+ e.getMessage());
		}
		actionForEach.setDefaultOrder(Globals.env.Sequential);

//		try {
//			modelActions.createActionTo$message(world,
//					new Selector(world.getClass(), "updateLattice", false));
//
//		} catch (Exception e) {
//			System.err.println("Exceção na atualização das intensiadades de feromônio: "
//					+ e.getMessage());
//		}
		modelSchedule = new ScheduleImpl(getZone(), 1);
		modelSchedule.at$createAction(0, modelActions);
		return this;
	}

	/*
	 * (non-Javadoc) Schedules devem ser ativados aqui
	 * 
	 * @see swarm.objectbase.SwarmImpl#activateIn(swarm.objectbase.Swarm)
	 */
	@Override
	public Activity activateIn(Swarm context) {
		super.activateIn(context);
		modelSchedule.activateIn(this);
		return getActivity();
	}

	/**
	 * Retorna a largura do mundo.
	 * 
	 * @return largura da grade bidimensional
	 */
	public int getGridWidth() {
		return world.getWidth();
	}

	/**
	 * Retorna a altura do mundo.
	 * 
	 * @return altura da grade bidimensional
	 */
	public int getGridHeight() {
		return world.getHeight();
	}

	/**
	 * Retorna a lista de formigas no ambiente.
	 * 
	 * @return lista dee formigas.
	 */
	public List<Ant> getAntList() {
		return antList;
	}

	/**
	 * Retorna a lista de objetos gráficos que aparecem na tela
	 * 
	 * @return lista de {@link GraphicObject}
	 */
	public List<GraphicObject> getGraphicObjects() {
		return graphicObjectsList;
	}

	/**
	 * Retorna o mundo da simulação
	 * 
	 * @return
	 */
	public AntWorld getWorld() {
		return this.world;
	}
}
